﻿using System;
using System.IO;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace NetFramework
{
    public class SocketClient : System.ComponentModel.Component, INetComponet
    {
        private int bufferSize = 2048;
        private string serverIP = "127.0.0.1";
        private int serverPort = 11000;
        private Socket ClientSocket = null;

        private ErrorEventArgs errArgs = new ErrorEventArgs("ConnectCallback");
        private ErrorEventArgs ArgsClose = new ErrorEventArgs("Colse");
        AsyncCallback ReceiveCall;

        private ManualResetEvent connectDone = new ManualResetEvent(false);
        private ManualResetEvent sendDone = new ManualResetEvent(false);

        protected virtual void OnConnectedEvent(ReceivedEventArgs e)
        {
            EvtConnected(this, e);
        }
        protected virtual void OnReceivedEvent(ReceivedEventArgs e)
        {
            EvtReceived(this, e);
        }
        protected virtual void OnSentEvent(EventArgs e)
        {
            EvtSent(this, e);
        }
        protected virtual void OnDisconnectEvent(EventArgs e)
        {
            EvtDisconnect(this, e);
        }
        protected virtual void OnCloseEvent(EventArgs e)
        {
            EvtClose(this, e);
        }
        protected virtual void OnTerminateEvent(EventArgs e)
        {
            EvtTerminate(this, e);
        }

        protected virtual void OnConnectedErrorEvent(ReceivedEventArgs e)
        {
            EvtConnectedError(this, e);
        }
        protected virtual void OnReceivedErrorEvent(ReceivedEventArgs e)
        {
            EvtReceivedError(this, e);
        }
        protected virtual void OnSentErrorEvent(EventArgs e)
        {
            EvtSentError(this, e);
        }
        protected virtual void OnDisconnectErrorEvent(EventArgs e)
        {
            EvtDisconnectError(this, e);
        }
        protected virtual void OnCloseErrorEvent(EventArgs e)
        {
            EvtCloseError(this, e);
        }
        protected virtual void OnTerminateErrorEvent(EventArgs e)
        {
            EvtTerminateError(this, e);
        }

        protected virtual void OnErrorEvent(ErrorEventArgs e)
        {
            EvtError(this, e);
        }

        public SocketClient(System.ComponentModel.IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        public SocketClient()
        {
            InitializeComponent();
            ReceiveCall = new AsyncCallback(ReceiveCallback);
        }

        public bool IsActive
        {
            get
            {
                if (ClientSocket == null)
                {
                    return false;
                }
                return ClientSocket.Connected;
            }
        }

        public void InitDevice(string ip, int port, int bufferSize)
        {
            this.bufferSize = bufferSize;
            this.serverIP = ip;
            this.serverPort = port;
        }

        public void Conn(string serverIP, int serverPort)
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(serverIP);
                IPEndPoint remoteEP = new IPEndPoint(ipAddress, serverPort);

                ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                connectDone.Reset();
                //throw new Exception();

                ClientSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), ClientSocket);
                connectDone.WaitOne();

            }
            catch (Exception e)
            {
                OnErrorEvent(new ErrorEventArgs(e, "conn"));
                connectDone.Set();
                //throw e;
            }
        }

        public IAsyncResult Connect(string serverIP, int serverPort)
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(serverIP);
                IPEndPoint remoteEP = new IPEndPoint(ipAddress, serverPort);

                ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                connectDone.Reset();
                ClientSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), ClientSocket);
                connectDone.WaitOne();

                StateObject state = new StateObject(bufferSize, ClientSocket);

                IAsyncResult iar = ClientSocket.BeginReceive(state.buffer, 0, bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                return iar;
            }
            catch (Exception e)
            {
                OnErrorEvent(new ErrorEventArgs(e, "asyn Connect"));
                throw e;
            }
        }

        public void Close()
        {
            try
            {
                if (ClientSocket.Connected == true)
                {
                    ClientSocket.Shutdown(SocketShutdown.Both);
                    ClientSocket.Close();
                }
            }
            catch (Exception e)
            {
                ArgsClose.SetException(e);
                OnCloseEvent(ArgsClose);
            }
        }

        public void Send(Stream Astream)
        {
            try
            {
                if (ClientSocket.Connected == false)
                {
                    throw (new Exception("没有连接服务器不可以发送信息!"));
                }
                Astream.Position = 0;
                byte[] byteData = new byte[bufferSize];
                int bi1 = (int)((Astream.Length + 8) / bufferSize);
                int bi2 = (int)Astream.Length;
                if (((Astream.Length + 8) % bufferSize) > 0)
                {
                    bi1 = bi1 + 1;
                }
                bi1 = bi1 * bufferSize;

                byteData[0] = System.Convert.ToByte(bi1 >> 24);
                byteData[1] = System.Convert.ToByte((bi1 & 0x00ff0000) >> 16);
                byteData[2] = System.Convert.ToByte((bi1 & 0x0000ff00) >> 8);
                byteData[3] = System.Convert.ToByte((bi1 & 0x000000ff));

                byteData[4] = System.Convert.ToByte(bi2 >> 24);
                byteData[5] = System.Convert.ToByte((bi2 & 0x00ff0000) >> 16);
                byteData[6] = System.Convert.ToByte((bi2 & 0x0000ff00) >> 8);
                byteData[7] = System.Convert.ToByte((bi2 & 0x000000ff));

                int n = Astream.Read(byteData, 8, byteData.Length - 8);

                while (n > 0)
                {
                    ClientSocket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), ClientSocket);
                    sendDone.WaitOne();

                    byteData = new byte[bufferSize];
                    n = Astream.Read(byteData, 0, byteData.Length);
                }
            }
            catch (Exception e)
            {
                OnErrorEvent(new ErrorEventArgs(e, "send"));
            }
        }

        public void Send(byte[] cmd)
        {
            try
            {
                if (ClientSocket.Connected == false)
                {
                    throw (new Exception("没有连接服务器不可以发送信息!"));
                }

                //while (cmd.Length > 0)
                {
                    ClientSocket.BeginSend(cmd, 0, cmd.Length, 0, new AsyncCallback(SendCallback), ClientSocket);
                    sendDone.WaitOne();

                }
            }
            catch (Exception e)
            {
                OnErrorEvent(new ErrorEventArgs(e, "send"));
            }
        }

        #region Component Designer generated code
        private void InitializeComponent()
        {

        }
        #endregion

        private void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                connectDone.Set();
                client.EndConnect(ar);

                OnConnectedEvent(null);

                StateObject state = new StateObject(bufferSize, ClientSocket);

                ClientSocket.BeginReceive(state.buffer, 0, bufferSize, 0, ReceiveCall, state);
            }
            catch (Exception e)
            {
                errArgs.SetException(e);
                OnErrorEvent(errArgs);
                //相当重要 如果不调用，EndConnect异常
                ar.AsyncWaitHandle.Close();
            }
        }
        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                int bytesSent = client.EndSend(ar);
            }
            catch (Exception e)
            {
                OnErrorEvent(new ErrorEventArgs(e, "SendCallback"));
            }
            finally
            {
                sendDone.Set();
            }
        }
        private void ReceiveCallback(IAsyncResult ar)
        {
            Socket handler = null;
            try
            {
                // lock (ar)
                {
                    StateObject state = (StateObject)ar.AsyncState;
                    handler = state.workSocket;

                    int bytesRead = handler.EndReceive(ar);


                    state.Datastream.Write(state.buffer, 0, bytesRead);


                    byte[] bytes = new byte[bytesRead];

                    for (int i = 0; i < bytes.Length; i++)
                    {
                        bytes[i] = state.buffer[i];
                    }
                    state.Datastream.Seek(0, SeekOrigin.Begin);

                    OnReceivedEvent(new ReceivedEventArgs(bytes));


                    #region
                    //if (bytesRead > 0)
                    //{
                    //    int ReadPiont = 0;
                    //    while (ReadPiont < bytesRead)
                    //    {
                    //        if (state.Cortrol == 0 && ReadPiont < bytesRead)
                    //        {
                    //          //  stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = (bi1 << 24) & 0xff000000;
                    //            state.packSize = bi1;
                    //            ReadPiont++;
                    //            state.Cortrol = 1;
                    //        }

                    //        if (state.Cortrol == 1 && ReadPiont < bytesRead)
                    //        {
                    //         //   stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = (bi1 << 16) & 0x00ff0000;
                    //            state.packSize = state.packSize + bi1;
                    //            ReadPiont++;
                    //            state.Cortrol = 2;
                    //        }

                    //        if (state.Cortrol == 2 && ReadPiont < bytesRead)
                    //        {
                    //          //  stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = (bi1 << 8) & 0x0000ff00;
                    //            state.packSize = state.packSize + bi1;
                    //            ReadPiont++;
                    //            state.Cortrol = 3;
                    //        }

                    //        if (state.Cortrol == 3 && ReadPiont < bytesRead)
                    //        {
                    //         //   stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = bi1 & 0xff;
                    //            state.packSize = state.packSize + bi1 - 4;
                    //            ReadPiont++;
                    //            state.Cortrol = 4;
                    //        }

                    //        if (state.Cortrol == 4 && ReadPiont < bytesRead)
                    //        {
                    //          //  stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = (bi1 << 24) & 0xff000000;
                    //            state.residualSize = bi1;
                    //            ReadPiont++;
                    //            state.Cortrol = 5;
                    //            state.packSize -= 1;
                    //        }

                    //        if (state.Cortrol == 5 && ReadPiont < bytesRead)
                    //        {
                    //          //  stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = (bi1 << 16) & 0x00ff0000;
                    //            state.residualSize = state.residualSize + bi1;
                    //            ReadPiont++;
                    //            state.Cortrol = 6;
                    //            state.packSize -= 1;
                    //        }

                    //        if (state.Cortrol == 6 && ReadPiont < bytesRead)
                    //        {
                    //          //  stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = (bi1 << 8) & 0x0000ff00;
                    //            state.residualSize = state.residualSize + bi1;
                    //            ReadPiont++;
                    //            state.Cortrol = 7;
                    //            state.packSize -= 1;
                    //        }
                    //        if (state.Cortrol == 7 && ReadPiont < bytesRead)
                    //        {
                    //          //  stateall = state;
                    //            long bi1 = state.buffer[ReadPiont];
                    //            bi1 = bi1 & 0xff;
                    //            state.residualSize = state.residualSize + bi1;
                    //            state.Datastream.SetLength(0);
                    //            state.Datastream.Position = 0;

                    //            ReadPiont++;
                    //            state.Cortrol = 8;
                    //            state.packSize -= 1;
                    //        }

                    //        if (state.Cortrol == 8 && ReadPiont < bytesRead)
                    //        {
                    //          //  stateall = state;
                    //            int bi1 = bytesRead - ReadPiont;
                    //            int bi2 = (int)(state.residualSize - state.Datastream.Length);
                    //            if (bi1 >= bi2)
                    //            {
                    //                state.Datastream.Write(state.buffer, ReadPiont, bi2);
                    //                ReadPiont += bi2;
                    //                byte[] bytes = new byte[bytesRead];

                    //                for (int i = 0; i < bytes.Length; i++)
                    //                {
                    //                    bytes[i] = state.buffer[i];
                    //                }
                    //                state.Datastream.Seek(0, SeekOrigin.Begin);
                    //                OnInceptEvent(new InceptEventArgs(bytes));
                    //                state.Cortrol = 9;
                    //                state.packSize -= bi2;
                    //            }
                    //            else
                    //            {
                    //                state.Datastream.Write(state.buffer, ReadPiont, bi1);
                    //                ReadPiont += bi1;

                    //                byte[] bytes = new byte[bytesRead];

                    //                for (int i = 0; i < bytes.Length; i++)
                    //                {
                    //                    bytes[i] = state.buffer[i];
                    //                }
                    //                state.Datastream.Seek(0, SeekOrigin.Begin);

                    //                OnInceptEvent(new InceptEventArgs(bytes));

                    //                //state.Cortrol = 9;//z

                    //                state.packSize -= bi1;

                    //            }
                    //        }
                    //        if (state.Cortrol == 9 && ReadPiont < bytesRead)
                    //        {
                    //         //   stateall = state;
                    //            int bi1 = bytesRead - ReadPiont;
                    //            if (bi1 < state.packSize)
                    //            {
                    //                state.packSize = state.packSize - bi1;
                    //                ReadPiont += bi1;
                    //            }
                    //            else
                    //            {
                    //                state.Cortrol = 0;
                    //                ReadPiont += (int)state.packSize;
                    //            }
                    //        }
                    //    }
                    //}
                    //else
                    //{
                    //   // throw (new Exception("读入的数据小于1bit"));
                    //}
                    #endregion

                    if (handler.Connected == true)
                    {
                        handler.BeginReceive(state.buffer, 0, bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                    }
                }
            }
            catch (Exception e)
            {
                OnErrorEvent(new ErrorEventArgs(e, "ReceiveCallback"));
            }
        }


        public event EventHandler EvtConnected = (s, e) => { };

        public event ReceivedEvent EvtReceived = (s, e) => { };

        public event EventHandler EvtSent = (s, e) => { };

        public event EventHandler EvtDisconnect = (s, e) => { };

        public event EventHandler EvtClose = (s, e) => { };

        public event EventHandler EvtTerminate = (s, e) => { };

        public event ErrorEvent EvtError = (s, e) => { };


        public event EventHandler EvtConnectedError = (s, e) => { };

        public event ReceivedEvent EvtReceivedError = (s, e) => { };

        public event EventHandler EvtSentError = (s, e) => { };

        public event EventHandler EvtCloseError = (s, e) => { };

        public event EventHandler EvtDisconnectError = (s, e) => { };

        public event EventHandler EvtTerminateError = (s, e) => { };
    }

    public class ReceivedEventArgs : EventArgs
    {
        private byte[] data;
        public byte[] Data
        {
            get { return data; }
            set { data = value; }

        }
        //private readonly Stream datastream;
        //private readonly Socket clientSocket;
        /**/
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="Astream">接收到的数据</param>
        /// <param name="ClientSocket">接收的插座</param>
        //public InceptEventArgs(Stream Astream, Socket ClientSocket)
        //{
        //    datastream = Astream;
        //    clientSocket = ClientSocket;
        //}
        //public InceptEventArgs(Stream Astream, byte[] d, Socket ClientSocket)
        //{
        //    data = new byte[d.Length];
        //    for (int i = 0; i < d.Length;i++ )
        //        data[i] = d[i];
        //    datastream = Astream;
        //    clientSocket = ClientSocket;
        //}
        public ReceivedEventArgs(byte[] d)
        {
            data = new byte[d.Length];
            for (int i = 0; i < d.Length; i++)
                data[i] = d[i];
        }
        ///**/
        ///// <summary>
        ///// 接受的数据流
        ///// </summary>
        //public Stream Astream
        //{
        //    get { return datastream; }
        //}
        ///**/
        ///// <summary>
        ///// 接收的插座
        ///// </summary>
        //public Socket ClientSocket
        //{
        //    get { return clientSocket; }
        //}
    }

    public delegate void ReceivedEvent(object sender, ReceivedEventArgs e);

    public class ErrorEventArgs : EventArgs
    {
        private Exception error;
        public string action = string.Empty;

        public ErrorEventArgs(string actionMsg)
        {
            this.action = actionMsg;
        }

        public ErrorEventArgs(Exception Error, string actionMsg)
        {
            error = Error;
            this.action = actionMsg;
        }

        public void SetException(Exception e)
        {
            error = e;
        }

        public Exception Error
        {
            get { return error; }
        }
    }

    public delegate void ErrorEvent(object sender, ErrorEventArgs e);

    public class StreamToByteHelper
    {
        public static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 设置当前流的位置为流的开始
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        public static Stream BytesToStream(byte[] bytes)
        {
            Stream stream = new MemoryStream(bytes);
            return stream;
        }

        public static void StreamToFile(Stream stream, string fileName)
        {
            // 把 Stream 转换成 byte[]
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 设置当前流的位置为流的开始
            stream.Seek(0, SeekOrigin.Begin);
            // 把 byte[] 写入文件
            FileStream fs = new FileStream(fileName, FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(bytes);
            bw.Close();
            fs.Close();
        }

        public static Stream FileToStream(string fileName)
        {
            // 打开文件
            FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            // 读取文件的 byte[]
            byte[] bytes = new byte[fileStream.Length];
            fileStream.Read(bytes, 0, bytes.Length);
            fileStream.Close();
            // 把 byte[] 转换成 Stream
            Stream stream = new MemoryStream(bytes);
            return stream;
        }
    }
}
